/**
 * 该插件可根据菜单配置自动生成 ANTD menu组件
 * menuOptions示例：
 * [
 *  {
 *    name: '菜单名称',
 *    path: '菜单路由',
 *    meta: {
 *      icon: '菜单图标',
 *      invisible: 'boolean, 是否不可见, 默认 false',
 *    },
 *    children: [子菜单配置]
 *  },
 *  {
 *    name: '菜单名称',
 *    path: '菜单路由',
 *    meta: {
 *      icon: '菜单图标',
 *      invisible: 'boolean, 是否不可见, 默认 false',
 *    },
 *    children: [子菜单配置]
 *  }
 * ]
 *
 * i18n: 国际化配置。系统默认会根据 options route配置的 path 和 name 生成英文以及中文的国际化配置，如需自定义或增加其他语言，配置
 * 此项即可。如：
 * i18n: {
 *   messages: {
 *     CN: {dashboard: {name: '监控中心'}}
 *     HK: {dashboard: {name: '監控中心'}}
 *   }
 * }
 **/
 import Menu from 'ant-design-vue/es/menu'
 import Icon from 'ant-design-vue/es/icon'
 import fastEqual from 'fast-deep-equal'
 // import {getI18nKey} from '@/utils/routerUtil'

 const {Item, SubMenu} = Menu

 const resolvePath = (path, params = {}) => {
   let _path = path
   Object.entries(params).forEach(([key, value]) => {
     _path = _path.replace(new RegExp(`:${key}`, 'g'), value)
   })
   return _path
 }

 const toRoutesMap = (routes) => {
   const map = {}
   routes.forEach(route => {
     map[route.fullPath] = route
     if (route.children && route.children.length > 0) {
       const childrenMap = toRoutesMap(route.children)
       Object.assign(map, childrenMap)
     }
   })
   return map
 }

 export default {
   name: 'IMenu',
   props: {
     options: {
       type: Array,
       required: true
     },
     theme: {
       type: String,
       required: false,
       default: 'dark'
     },
     mode: {
       type: String,
       required: false,
       default: 'inline'
     },
     collapsed: {
       type: Boolean,
       required: false,
       default: false
     },
     i18n: Object,
     openKeys: Array
   },
   data () {
     return {
       selectedKeys: [],
       sOpenKeys: [],
       cachedOpenKeys: []
     }
   },
   computed: {
     menuTheme() {
       return this.theme === 'light' ? this.theme : 'dark'
     },
     routesMap() {
       return toRoutesMap(this.options)
     }
   },
   created () {
     if (this.options.length > 0 && !this.options[0].fullPath) {
       this.formatOptions(this.options, '')
     }
     this.updateMenu()
     // 自定义国际化配置
     if(this.i18n && this.i18n.messages) {
       const messages = this.i18n.messages
       Object.keys(messages).forEach(key => {
         this.$i18n.mergeLocaleMessage(key, messages[key])
       })
     }
   },
   watch: {
     options(val) {
       if (val.length > 0 && !val[0].fullPath) {
         this.formatOptions(this.options, '')
       }
     },
     i18n(val) {
       if(val && val.messages) {
         const messages = this.i18n.messages
         Object.keys(messages).forEach(key => {
           this.$i18n.mergeLocaleMessage(key, messages[key])
         })
       }
     },
     collapsed (val) {
       if (val) {
         this.cachedOpenKeys = this.sOpenKeys
         this.sOpenKeys = []
       } else {
         this.sOpenKeys = this.cachedOpenKeys
       }
     },
     '$route': function () {
       this.updateMenu()
     },
     sOpenKeys(val) {
       this.$emit('openChange', val)
       this.$emit('update:openKeys', val)
     }
   },
   methods: {
     renderIcon: function (h, icon, key) {
       if (this.$scopedSlots.icon && icon && icon !== 'none') {
         const vnodes = this.$scopedSlots.icon({icon, key})
         vnodes.forEach(vnode => {
           vnode.data.class = vnode.data.class ? vnode.data.class : []
           vnode.data.class.push('anticon')
         })
         return vnodes
       }
       return !icon || icon === 'none' ? null : h(Icon, {props: {type:  icon}})
     },
     renderMenuItem: function (h, menu) {
       let tag = 'router-link'
       const path = resolvePath(menu.fullPath, menu.meta.params)
       let config = {props: {to: {path, query: menu.meta.query}, }, attrs: {style: 'overflow:hidden;white-space:normal;text-overflow:clip;'}}
       if (menu.meta && menu.meta.link) {
         tag = 'a'
         config = {attrs: {style: 'overflow:hidden;white-space:normal;text-overflow:clip;', href: menu.meta.link, target: '_blank'}}
       }
       return h(
         Item, {key: menu.fullPath},
         [
           h(tag, config,
             [
               // this.renderIcon(h, menu.meta ? menu.meta.icon : 'none', menu.fullPath),
               menu.meta.title
             ]
           )
         ]
       )
     },
     renderSubMenu: function (h, menu) {
       let this_ = this
       let subItem = [h('span', {slot: 'title', attrs: {style: 'overflow:hidden;white-space:normal;text-overflow:clip;'}},
         [
           // this.renderIcon(h, menu.meta ? menu.meta.icon : 'none', menu.fullPath),
           menu.meta.title
         ]
       )]
       let itemArr = []
       menu.children.forEach(function (item) {
         itemArr.push(this_.renderItem(h, item))
       })
       return h(SubMenu, {key: menu.fullPath},
         subItem.concat(itemArr)
       )
     },
     renderItem: function (h, menu) {
       const meta = menu.meta
       if (!meta || !meta.invisible) {
         let renderChildren = false
         const children = menu.children
         if (children !== undefined) {
           for (let i = 0; i < children.length; i++) {
             const childMeta = children[i].meta
             if (!childMeta || !childMeta.invisible) {
               renderChildren = true
               break
             }
           }
         }
         return (menu.children && renderChildren) ? this.renderSubMenu(h, menu) : this.renderMenuItem(h, menu)
       }
     },
     renderMenu: function (h, menuTree) {
       let this_ = this
       let menuArr = []
       menuTree.forEach(function (menu, i) {
         menuArr.push(this_.renderItem(h, menu, '0', i))
       })
       return menuArr
     },
     formatOptions(options, parentPath) {
       options.forEach(route => {
         let isFullPath = route.path.substring(0, 1) === '/'
         route.fullPath = isFullPath ? route.path : parentPath + '/' + route.path
         if (route.children) {
           this.formatOptions(route.children, route.fullPath)
         }
       })
     },
     updateMenu () {
       this.selectedKeys = this.getSelectedKeys()
       let openKeys = this.selectedKeys.filter(item => item !== '')
       openKeys = openKeys.slice(0, openKeys.length -1)
       if (!fastEqual(openKeys, this.sOpenKeys)) {
         this.collapsed || this.mode === 'horizontal' ? this.cachedOpenKeys = openKeys : this.sOpenKeys = openKeys
       }
     },
     getSelectedKeys() {
       let matches = this.$route.matched
       const route = matches[matches.length - 1]
       let chose = this.routesMap[route.path]
       if (chose.meta && chose.meta.highlight) {
         chose = this.routesMap[chose.meta.highlight]
         const resolve = this.$router.resolve({path: chose.fullPath})
         matches = (resolve.resolved && resolve.resolved.matched) || matches
       }
       return matches.map(item => item.path)
     }
   },
   render (h) {
     return h(
       Menu,
       {
         props: {
           theme: this.menuTheme,
           mode: this.$props.mode,
           selectedKeys: this.selectedKeys,
           openKeys: this.openKeys ? this.openKeys : this.sOpenKeys
         },
         on: {
           'update:openKeys': (val) => {
             this.sOpenKeys = val
           },
           click: (obj) => {
             obj.selectedKeys = [obj.key]
             this.$emit('select', obj)
           }
         }
       }, this.renderMenu(h, this.options)
     )
   }
 }
